package com.autocloud.filter;

import com.autocloud.domain.LogOriginalRepository;
import com.autocloud.model.log.LogOriginal;
import com.google.gson.Gson;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;

/**
 * @author zhongwb
 * @version 1.0
 * @description
 * @date 2019/12/2 11:52 下午
 */
public class RequestTimeGatewayFilterFactory extends
        AbstractGatewayFilterFactory<RequestTimeGatewayFilterFactory.Config> {

    private static final Log log = LogFactory.getLog(GatewayFilter.class);
    private static final String REQUEST_TIME_BEGIN = "requestTimeBegin";
    private static final String KEY = "withParams";

    @Autowired
    LogOriginalRepository logOriginalRepository;

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList(KEY);
    }

    public RequestTimeGatewayFilterFactory() {
        super(Config.class);
    }

    Gson gson = new Gson();

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            Object requestBody = exchange.getAttribute("cachedRequestBodyObject");
            final String body = requestBody != null ? gson.toJson(requestBody) : null;
            exchange.getAttributes().put(REQUEST_TIME_BEGIN, System.currentTimeMillis());
            return chain.filter(exchange).then(
                    Mono.fromRunnable(() -> {
                        Long startTime = exchange.getAttribute(REQUEST_TIME_BEGIN);
                        if (startTime != null) {
                            HttpHeaders headers = exchange.getRequest().getHeaders();
                            String url = exchange.getRequest().getURI().getRawPath();
                            double elapsedtime = System.currentTimeMillis() - startTime;
                            String ipaddress = exchange.getRequest().getRemoteAddress().getHostString();
                            String origin = headers.get("Origin") == null ? "" : String.join(",", headers.get("Origin"));
                            String Agent = headers.get("User-Agent") == null ? "" : String.join(",", headers.get("User-Agent"));
                            String Language = headers.get("Accept-Language") == null ? "" : String.join(",", headers.get("Accept-Language"));
                            String orgunit = headers.get("Authorization-orgunit") == null ? "" : String.join(",", headers.get("Authorization-orgunit"));
                            String account = headers.get("Authorization-account") == null ? "" : String.join(",", headers.get("Authorization-account"));
                            StringBuilder sb = new StringBuilder()
                                    .append(String.format("\n 请求地址:%s :\n 请求耗时:%s ms"
                                            , url
                                            , elapsedtime));
                            sb.append(String.format("\n 客户端IP:%s \n Origin: %s,\n客户环境: %s,\n 语言: %s,\n 用户组织:%s,\n 用户账号:%s",
                                    ipaddress,
                                    origin
                                    , Agent
                                    , Language
                                    , orgunit
                                    , account));
                            LogOriginal logOriginal = LogOriginal.of(url, elapsedtime, ipaddress, origin, Agent, Language, orgunit, account, body);
                            logOriginalRepository.save(logOriginal);
                        }
                    })
            );
        };
    }

    public static class Config {

        private boolean withParams;

        public boolean isWithParams() {
            return withParams;
        }

        public void setWithParams(boolean withParams) {
            this.withParams = withParams;
        }

    }
}
